package services

import (
	"TaskAssignmentSystem/internal/admin/dao"
	"TaskAssignmentSystem/internal/pkg/code"
	"TaskAssignmentSystem/internal/pkg/task"
	"TaskAssignmentSystem/pkg/db/mysql"
	"TaskAssignmentSystem/pkg/db/redis"
	"TaskAssignmentSystem/pkg/oss"
	"TaskAssignmentSystem/pkg/timehandler"
	"TaskAssignmentSystem/pkg/utils"
	"errors"
	"fmt"
	"github.com/go-co-op/gocron"
	jsoniter "github.com/json-iterator/go"
	"gorm.io/gorm"
	"sync"
	"time"
)

/*
 * TaskType 类型: 0->题目答题倒计时,管理员导入表格处理数据时的任务;1->指派;2->回归题库;3->返修;4->作废;5->题目生效时间更改题目状态;6->题目截止时间过期更改题目状态
 * Topic状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废
 */

type TopicService struct{}

/*
 * 删除题目
 */

func (d *TopicService) RemoveById(id uint) (err error) {
	var topicServe CommonService[dao.SystemTopic]
	topicServe.Query = map[string]interface{}{"id": id}
	_db := mysql.GetDB()
	err = _db.Transaction(func(tx *gorm.DB) error {
		topicServe.Tx = tx
		var topic dao.SystemTopic
		if err := tx.Model(dao.SystemTopic{}).Where(map[string]interface{}{"id": id}).First(&topic).Error; err != nil {
			return err
		}
		var common dao.Common[dao.SystemTopic]
		common.Tx = tx
		common.Query = topicServe.Query
		//删除题目配置
		if err := tx.Unscoped().Where("system_topic_id IN (?)", topic.Id).Delete(&dao.TopicNote{}).Error; err != nil {
			return err
		}
		//删除题目与用户的记录
		if err := tx.Unscoped().Where("system_topic_id IN (?)", topic.Id).Delete(&dao.TopicUserRecord{}).Error; err != nil {
			return err
		}
		//删除题目的配置选项
		if err := tx.Unscoped().Where("system_topic_id IN (?)", topic.Id).Delete(&dao.TopicConfiguration{}).Error; err != nil {
			return err
		}
		//删除相关配置答案
		if err := tx.Model(&dao.TopicAnswer{}).Unscoped().Where("system_topic_id IN (?)", topic.Id).Delete(&dao.TopicAnswer{}).Error; err != nil {
			return err
		}
		//删除题目
		if err := common.RemoveUnscopedPreload(common.Query).Error; err != nil {
			return err
		}
		//更新项目表中对应的题目数
		var projectDao dao.Common[dao.SystemProject]
		projectDao.Tx = tx
		projectDao.Query = map[string]interface{}{"project_id": topic.ProjectId}
		if err := projectDao.Update(map[string]interface{}{"topic_count": gorm.Expr("topic_count - ?", 1)}).Error; err != nil {
			return err
		}
		//删除题目答案的存储目录
		bucketClient := oss.BucketClient{}
		fmt.Println("oss path", fmt.Sprintf("task-assign/%s/%s", topic.ProjectId, topic.TopicId))
		go bucketClient.BatchRemoveFiles(fmt.Sprintf("task-assign/%s/%s", topic.ProjectId, topic.TopicId))

		return nil
	})
	return err
}

//批量删除单个项目的多个题目

func (d *TopicService) BatchRemoveAllTopic(projectId string, ids []uint) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		var common dao.Common[dao.SystemTopic]
		common.Tx = tx

		topicIds := ids
		count, err := common.Count(map[string]interface{}{"id": ids})
		if err != nil {
			return err
		}
		if count == 0 {
			return nil
		}
		//删除题目备注
		if err := tx.Model(&dao.TopicNote{}).Unscoped().Where("system_topic_id IN (?)", topicIds).Delete(&dao.TopicNote{}).Error; err != nil {
			return err
		}
		if err := tx.Unscoped().Where("system_topic_id IN (?)", topicIds).Delete(&dao.TopicUserRecord{}).Error; err != nil {
			return err
		}
		//删除题目配置
		if err := tx.Model(&dao.TopicConfiguration{}).Unscoped().Where("system_topic_id IN (?)", topicIds).Delete(&dao.TopicConfiguration{}).Error; err != nil {
			return err
		}
		//删除相关配置答案
		if err := tx.Model(&dao.TopicAnswer{}).Unscoped().Where("system_topic_id IN (?)", topicIds).Delete(&dao.TopicAnswer{}).Error; err != nil {
			return err
		}
		//删除相关题目
		var topics []dao.SystemTopic
		if err := tx.Model(&dao.SystemTopic{}).Unscoped().Where("id IN (?)", ids).Delete(&topics).Error; err != nil {
			return err
		}
		//更新项目表中题目数
		var projectDao dao.Common[dao.SystemProject]
		projectDao.Tx = tx
		projectDao.Query = map[string]interface{}{"project_id": projectId}
		if err := projectDao.Update(map[string]interface{}{"topic_count": gorm.Expr("topic_count - ?", count)}).Error; err != nil {
			return err
		}

		for _, topic := range topics {
			//删除题目答案的存储目录
			bucketClient := oss.BucketClient{}
			go bucketClient.BatchRemoveFiles(fmt.Sprintf("task-assign/%s/%s", topic.ProjectId, topic.TopicId))
		}
		return nil
	})
}

/*
 * 维护题目的状态
 * Topic状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废 7 已失效
 */

func (d *TopicService) ChangeStatus(Id uint, status int) error {
	var topicServe dao.Common[dao.SystemTopic]
	topicServe.Query = map[string]interface{}{"id": Id}
	var set map[string]interface{}
	switch status {
	case 5: //回归题库
		return d.RegressionQuestionBank(Id, time.Now().Add(-1*time.Minute))
	case 4: //返修
		return d.TopicRepair(Id, time.Now().Add(-1*time.Minute))
	case 6: //作废
		return d.InvalidTopic(Id, time.Now().Add(-1*time.Minute))
	default:
		set = map[string]interface{}{}
	}
	return topicServe.Update(set).Error
}

func (d *TopicService) NewBatchInsertTopic(topic dao.SystemTopic) {
	var projectDao dao.Common[dao.SystemProject]
	mysql.GetDB().Transaction(func(tx *gorm.DB) error {
		//处理时间当前题目的生效时间，当生效时间在当前时间的前面则修改状态为闲置中
		if topic.EffectiveTime.After(time.Now().In(utils.LocationZone)) {
			//TODO
			//未生效
			topic.Status = 0
		} else {
			if topic.EndDateTime.After(time.Now().In(utils.LocationZone)) {
				topic.Status = 5
			} else {
				//导入题目的截止时间已经在当前时间之前 已失效
				topic.Status = 7
			}
		}
		err := tx.Model(&dao.SystemTopic{}).Create(&topic).Error
		if err != nil {
			return err
		}
		if topic.EndDateTime.After(time.Now().In(utils.LocationZone)) {
			//if topic.EndDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	expiration := topic.EndDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	//key := fmt.Sprintf("task_topic_%d", topic.Id)
			//	key := utils.GenerateRedisKey(topic.Id, fmt.Sprintf("6"))
			//	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 6, "status": 7})
			//	if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//		return setNX
			//	}
			//} else {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 6
			task.SystemTopicId = topic.Id
			task.ExecutionDateTime = topic.EndDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 6, "status": 7}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}
		}
		if time.Now().Before(topic.EffectiveTime) {
			//if topic.EffectiveTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	//expiration := topic.EffectiveTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	////key := fmt.Sprintf("task_topic_%d", topic.Id)
			//	//key := utils.GenerateRedisKey(topic.Id, fmt.Sprintf("2"))
			//	//value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 2, "status": 5})
			//	//if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//	//	return setNX
			//	//}
			//
			//	/*
			//		gocron定时任务
			//	*/
			//
			//	timezone, _ := time.LoadLocation("Asia/Shanghai")
			//	s := gocron.NewScheduler(timezone)
			//	s.Every(1).Day().At(topic.EffectiveTime.Format("15:04:05")).Do(func(topicId uint, status int) {
			//		go task.TopicToTakeEffect([]uint{topicId}, status)
			//	}, topic.Id, 5)
			//	s.StartAsync()
			//
			//} else {
			//	//创建一个倒计时任务
			//	var task dao.SystemTask
			//	task.TaskType = 5
			//	task.SystemTopicId = topic.Id
			//	task.ExecutionDateTime = topic.EffectiveTime
			//	task.ExecutionData = map[string]interface{}{"task_type": 5, "status": 5}
			//	if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
			//		return err
			//	}
			//}

			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 5
			task.SystemTopicId = topic.Id
			task.ExecutionDateTime = topic.EffectiveTime
			task.ExecutionData = map[string]interface{}{"task_type": 5, "status": 5}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
		}

		projectDao.Query = map[string]interface{}{"project_id": topic.ProjectId}
		projectDao.Tx = tx
		//更改项目表中的题目数
		if err := projectDao.Update(map[string]interface{}{"topic_count": gorm.Expr("topic_count + ?", 1)}).Error; err != nil {
			return err
		}
		return nil
	})
}

//批量插入题目

func (d *TopicService) BatchInsertTopic(ch chan error, topic dao.SystemTopic, wg *sync.WaitGroup) {
	defer wg.Done()
	var projectDao dao.Common[dao.SystemProject]
	err := mysql.GetDB().Transaction(func(tx *gorm.DB) error {
		//处理时间当前题目的生效时间，当生效时间在当前时间的前面则修改状态为闲置中
		if topic.EffectiveTime.After(time.Now().In(utils.LocationZone)) {
			//TODO
			//未生效
			topic.Status = 0
		} else {
			if topic.EndDateTime.After(time.Now().In(utils.LocationZone)) {
				topic.Status = 5
			} else {
				//导入题目的截止时间已经在当前时间之前 已失效
				topic.Status = 7
			}
		}
		err := tx.Model(&dao.SystemTopic{}).Create(&topic).Error
		if err != nil {
			return err
		}
		if topic.EndDateTime.After(time.Now().In(utils.LocationZone)) {
			//if topic.EndDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	expiration := topic.EndDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	//key := fmt.Sprintf("task_topic_%d", topic.Id)
			//	key := utils.GenerateRedisKey(topic.Id, fmt.Sprintf("6"))
			//	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 6, "status": 7})
			//	if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//		return setNX
			//	}
			//} else {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 6
			task.SystemTopicId = topic.Id
			task.ExecutionDateTime = topic.EndDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 6, "status": 7}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}
		}
		if time.Now().Before(topic.EffectiveTime) {
			//if topic.EffectiveTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	//expiration := topic.EffectiveTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	////key := fmt.Sprintf("task_topic_%d", topic.Id)
			//	//key := utils.GenerateRedisKey(topic.Id, fmt.Sprintf("2"))
			//	//value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 2, "status": 5})
			//	//if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//	//	return setNX
			//	//}
			//
			//	/*
			//		gocron定时任务
			//	*/
			//
			//	timezone, _ := time.LoadLocation("Asia/Shanghai")
			//	s := gocron.NewScheduler(timezone)
			//	s.Every(1).Day().At(topic.EffectiveTime.Format("15:04:05")).Do(func(topicId uint, status int) {
			//		go task.TopicToTakeEffect([]uint{topicId}, status)
			//	}, topic.Id, 5)
			//	s.StartAsync()
			//
			//} else {
			//	//创建一个倒计时任务
			//	var task dao.SystemTask
			//	task.TaskType = 5
			//	task.SystemTopicId = topic.Id
			//	task.ExecutionDateTime = topic.EffectiveTime
			//	task.ExecutionData = map[string]interface{}{"task_type": 5, "status": 5}
			//	if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
			//		return err
			//	}
			//}

			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 5
			task.SystemTopicId = topic.Id
			task.ExecutionDateTime = topic.EffectiveTime
			task.ExecutionData = map[string]interface{}{"task_type": 5, "status": 5}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
		}

		projectDao.Query = map[string]interface{}{"project_id": topic.ProjectId}
		projectDao.Tx = tx
		//更改项目表中的题目数
		if err := projectDao.Update(map[string]interface{}{"topic_count": gorm.Expr("topic_count + ?", 1)}).Error; err != nil {
			return err
		}
		return nil
	})
	ch <- err
}

/*
 * 插入题目
 */

func (d *TopicService) InsertTopic(topic dao.SystemTopic) error {
	var projectDao dao.Common[dao.SystemProject]
	var _db = mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		//处理时间当前题目的生效时间，当生效时间在当前时间的前面则修改状态为闲置中
		if topic.EffectiveTime.After(time.Now().In(utils.LocationZone)) {
			//TODO
			//未生效
			topic.Status = 0
		} else {
			if topic.EndDateTime.After(time.Now().In(utils.LocationZone)) {
				topic.Status = 5
			} else {
				//导入题目的截止时间已经在当前时间之前
				topic.Status = 6
			}
		}
		err := tx.Model(&dao.SystemTopic{}).Create(&topic).Error
		if err != nil {
			return err
		}
		if time.Now().Before(topic.EffectiveTime) {
			//if topic.EffectiveTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	expiration := topic.EffectiveTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	//key := fmt.Sprintf("task_topic_%d", topic.Id)
			//	key := utils.GenerateRedisKey(topic.Id, fmt.Sprintf("2"))
			//	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 2, "status": 5})
			//	if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//		return setNX
			//	}
			//} else {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 5
			task.SystemTopicId = topic.Id
			task.ExecutionDateTime = topic.EffectiveTime
			task.ExecutionData = map[string]interface{}{"task_type": 5, "status": 5}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}
		}

		projectDao.Query = map[string]interface{}{"project_id": topic.ProjectId}
		projectDao.Tx = tx
		//更改项目表中的题目数
		if err := projectDao.Update(map[string]interface{}{"topic_count": gorm.Expr("topic_count + ?", 1)}).Error; err != nil {
			return err
		}
		return nil
	})
}

/*
 * 作废题目
 * TaskType 类型: 0->题目答题倒计时,管理员导入表格处理数据时的任务;1->指派;2->回归题库;3->返修;4->作废;5->题目生效时间更改题目状态;6->题目截止时间过期更改题目状态
 * Topic状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废
 */

func (d *TopicService) InvalidTopic(topicId uint, ExecutionDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				//key := fmt.Sprintf("task_topic_%d", topicId)
				key := utils.GenerateRedisKey(topicId, fmt.Sprintf("4"))
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 4, "status": 6})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 2
				task.SystemTopicId = topicId
				task.ExecutionDateTime = ExecutionDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 4, "status": 6}
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		} else {
			var topicAnswerServe TopicAnswerService
			go topicAnswerServe.OneInvalidTopic([]uint{topicId})
		}
		return nil
	})

}

func (d *TopicService) BatchInvalidTopic(ch chan error, topic dao.SystemTopic, ExecutionDateTime time.Time, wg *sync.WaitGroup) {
	_db := mysql.GetDB()

	err := _db.Transaction(func(tx *gorm.DB) error {
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			//if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	//key := fmt.Sprintf("task_topic_%d", topicId)
			//	key := utils.GenerateRedisKey(topic.Id, fmt.Sprintf("4"))
			//	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 4, "status": 6})
			//	if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//		return setNX
			//	}
			//} else {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 4
			task.SystemTopicId = topic.Id
			task.ExecutionDateTime = ExecutionDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 4, "status": 6}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}
		} else {
			var topicAnswerServe TopicAnswerService
			if err := topicAnswerServe.BatchInvalidTopic(topic); err != nil {
				return err
			}
		}
		return nil
	})
	ch <- err
	wg.Done()
}

/*
 * 回归题库
 * TaskType 类型: 0->题目答题倒计时,管理员导入表格处理数据时的任务;1->指派;2->回归题库;3->返修;4->作废;5->题目生效时间更改题目状态;6->题目截止时间过期更改题目状态
 * Topic状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废 7 已失效
 */

func (d *TopicService) RegressionQuestionBank(topicId uint, ExecutionDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		fmt.Sprintf("%d--%s", topicId, ExecutionDateTime)
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				/*
					gocron定时任务
				*/
				timezone, _ := time.LoadLocation("Asia/Shanghai")
				s := gocron.NewScheduler(timezone)
				s.Every(1).Day().At(ExecutionDateTime.Format("15:04:05")).Do(func(topicId uint, status int) {
					go task.TopicToTakeEffect([]uint{topicId})
				}, topicId, 5)

			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 2
				task.SystemTopicId = topicId
				task.ExecutionDateTime = ExecutionDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 2, "status": 5}
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		} else {
			//删除之前的答案 更改状态
			fmt.Sprintf("%d", topicId)
			var topicAnswerServe TopicAnswerService
			if err := topicAnswerServe.RegressionQuestionBank(topicId); err != nil {
				return err
			}
		}
		return nil
	})
}

// 题目生效

func (d *TopicService) TopicToTakeEffect(topicId uint, ExecutionDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		fmt.Sprintf("%d--%s", topicId, ExecutionDateTime)
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				/*
					gocron定时任务
				*/
				timezone, _ := time.LoadLocation("Asia/Shanghai")
				s := gocron.NewScheduler(timezone)
				s.Every(1).Day().At(ExecutionDateTime.Format("15:04:05")).Do(func(topicId uint, status int) {
					go task.TopicToTakeEffect([]uint{topicId})
				}, topicId, 5)

			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 2
				task.SystemTopicId = topicId
				task.ExecutionDateTime = ExecutionDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 2, "status": 5}
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		} else {
			//删除之前的答案 更改状态
			fmt.Sprintf("%d", topicId)
			var topicAnswerServe TopicAnswerService
			if err := topicAnswerServe.RegressionQuestionBank(topicId); err != nil {
				return err
			}
		}
		return nil
	})
}

//批量回归题库

func (d *TopicService) BatchRegressionQuestionBank(topicId uint, ExecutionDateTime time.Time, EndDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {

		//删除之前的任务
		tx.Model(&dao.SystemTask{}).Where(map[string]interface{}{"system_topic_id": topicId}).Delete(&dao.SystemTask{})
		//删除redis中的定时失效任务
		redis.RedisGClient.Del(fmt.Sprintf("task_topic@%d_%s", topicId, "6"))
		//删除redis中的定时生效任务
		redis.RedisGClient.Del(fmt.Sprintf("task_topic@%d_%s", topicId, "5"))
		//移除之前的任务--回归题库
		redis.RedisGClient.Del(fmt.Sprintf("task_topic@%d_%s", topicId, "2"))
		var status int
		if ExecutionDateTime.In(utils.LocationZone).After(time.Now().In(utils.LocationZone)) {
			status = 0
		} else {
			status = 5
		}
		tx.Model(&dao.SystemTopic{}).Where(map[string]interface{}{"id": topicId}).Updates(map[string]interface{}{"status": status, "effective_time": ExecutionDateTime, "end_date_time": EndDateTime})
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 2
			task.SystemTopicId = topicId
			task.ExecutionDateTime = ExecutionDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 2, "status": 5}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}
		} else {
			//删除之前的答案 更改状态
			var topicAnswerServe TopicAnswerService
			go topicAnswerServe.BatchRegressionQuestionBank([]uint{topicId})
		}

		//截止时间处理
		go d.RegressionQuestionClose(topicId, EndDateTime)

		return nil
	})
}

// 题目失效处理

func (d *TopicService) RegressionQuestionClose(topicId uint, ExecutionDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			//if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//
			//	key := utils.GenerateRedisKey(topicId, fmt.Sprintf("6"))
			//	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 6, "status": 7})
			//	if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//		return setNX
			//	}
			//} else {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 6
			task.SystemTopicId = topicId
			task.ExecutionDateTime = ExecutionDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 6, "status": 7}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}
		} else {
			var topicDao dao.Common[dao.SystemTopic]
			topicDao.Query = map[string]interface{}{"id": topicId, "status": []int{0, 2, 3, 4, 5}} //已完成和已作废的 不做失效处理
			if err := topicDao.Update(map[string]interface{}{"status": 7}).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

//批量指派

func (d *TopicService) BatchAssignUser(ch chan error, topicId string, projectId string, userId string, ExecutionDateTime time.Time, EndDateTime time.Time, wg *sync.WaitGroup) {
	defer wg.Done()
	_db := mysql.GetDB()
	err := _db.Transaction(func(tx *gorm.DB) error {
		var topicDao dao.Common[dao.SystemTopic]
		topicDao.Tx = tx
		topicDao.Query = map[string]interface{}{"topic_id": topicId, "project_id": projectId, "status": []int{0, 1, 2, 3, 4, 5, 7}}
		topic, err := topicDao.First(topicDao.Query)
		if err != nil {
			return err
		}
		//删除之前的任务
		tx.Model(&dao.SystemTask{}).Unscoped().Where(map[string]interface{}{"system_topic_id": topic.Id}).Delete(&dao.SystemTask{})

		//删除redis中的定时失效任务
		code.RemoveRedisKeys(fmt.Sprintf("task_topic@%d", topic.Id))

		//更新题目的生效时间和截止时间
		var status int
		if ExecutionDateTime.In(utils.LocationZone).After(time.Now().In(utils.LocationZone)) {
			status = 3
		} else {
			if EndDateTime.In(utils.LocationZone).After(time.Now().In(utils.LocationZone)) {
				status = 3
			} else {
				status = 7
			}
		}
		tx.Model(&dao.SystemTopic{}).Where(map[string]interface{}{"id": topic.Id}).Updates(map[string]interface{}{"status": status, "effective_time": ExecutionDateTime, "end_date_time": EndDateTime})

		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 1
			task.SystemTopicId = topic.Id
			task.ExecutionDateTime = ExecutionDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 1, "status": 3, "user_id": userId, "project_id": projectId, "end_date_time": EndDateTime}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}

		} else {
			var project dao.SystemProject
			if err := tx.Model(&dao.SystemProject{}).Where("project_id = ?", projectId).First(&project).Error; err != nil {
				return err
			}

			//添加用户记录
			var topic_user_record dao.TopicUserRecord
			topic_user_record.TopicId = topicId
			topic_user_record.UserId = userId
			topic_user_record.ProjectId = projectId
			topic_user_record.SystemTopicId = topic.Id
			topic_user_record.Tp = 1

			if err := tx.Model(&dao.TopicUserRecord{}).Create(&topic_user_record).Error; err != nil {
				return err
			}
			var finish_time time.Time

			if time.Now().Add(time.Duration(project.CountdownAnswer) * time.Second).In(utils.LocationZone).After(EndDateTime) {
				finish_time = EndDateTime
			} else {
				finish_time = time.Now().Add(time.Duration(project.CountdownAnswer) * time.Second).In(utils.LocationZone)
			}

			if finish_time.After(project.OfflineDateTime) {
				finish_time = project.OfflineDateTime
			}

			if err := topicDao.Update(map[string]interface{}{"receiver_id": userId, "status": 3, "finish_time": finish_time}).Error; err != nil {
				return err
			}

			//加上一个答题倒计时
			go d.TopicCountdownAnswer(topic.Id, finish_time)
		}

		go d.RegressionQuestionClose(topic.Id, EndDateTime)
		return nil
	})
	ch <- err
}

/*
 * 指派题目给某位用户
 * TaskType 类型: 0->题目答题倒计时,管理员导入表格处理数据时的任务;1->指派;2->回归题库;3->返修;4->作废;5->题目生效时间更改题目状态;6->题目截止时间过期更改题目状态
 * Topic状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废
 */

func (d *TopicService) TopicAssignUser(topicId uint, userId string, ExecutionDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {

		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			//if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	//key := fmt.Sprintf("task_topic_%d", topicId)
			//	key := utils.GenerateRedisKey(topicId, fmt.Sprintf("1_%s", userId))
			//	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 1, "status": 3, "user_id": userId})
			//	if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//		return setNX
			//	}
			//} else {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 1
			task.SystemTopicId = topicId
			task.ExecutionDateTime = ExecutionDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 1, "status": 3, "user_id": userId}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}

		} else {
			var topicDao dao.Common[dao.SystemTopic]
			topicDao.Tx = tx
			topicDao.Query = map[string]interface{}{"id": topicId, "status": []int{0, 1, 2, 3, 4, 5, 6}}
			var project dao.SystemProject
			systemTopic, err := topicDao.First(topicDao.Query)
			if err != nil {
				return err
			}
			tx.Model(&dao.SystemProject{}).Where("project_id = ?", systemTopic.ProjectId).First(&project)

			//添加用户记录
			var topic_user_record dao.TopicUserRecord
			topic_user_record.TopicId = systemTopic.TopicId
			topic_user_record.UserId = userId
			topic_user_record.ProjectId = systemTopic.ProjectId
			topic_user_record.SystemTopicId = systemTopic.Id
			topic_user_record.Tp = 1
			if err := tx.Model(&dao.TopicUserRecord{}).Create(&topic_user_record).Error; err != nil {
				return err
			}
			if err := topicDao.Update(map[string]interface{}{"receiver_id": userId, "status": 3, "finish_time": ExecutionDateTime.Add(time.Second * time.Duration(project.CountdownAnswer))}).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

/*
 * 返修
 * TaskType 类型: 0->题目答题倒计时,管理员导入表格处理数据时的任务;1->指派;2->回归题库;3->返修;4->作废;5->题目生效时间更改题目状态;6->题目截止时间过期更改题目状态
 * Topic状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废,7已失效
 * 返修截止时间，超过截止时间，自动回归题库
 */

func (d *TopicService) TopicRepair(topicId uint, ExecutionDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				//key := fmt.Sprintf("task_topic_%d", topicId)
				key := utils.GenerateRedisKey(topicId, fmt.Sprintf("3"))
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 3, "status": 4})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 3
				task.SystemTopicId = topicId
				task.ExecutionDateTime = ExecutionDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 3, "status": 4} //返修截止时间，超过截止时间，自动回归题库
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		} else {
			if err := func(tx *gorm.DB) error {
				var topicDao dao.Common[dao.SystemTopic]
				topicDao.Tx = tx
				topicDao.Query = map[string]interface{}{"id": topicId, "status": 1} //该题目必须是已经完成的
				topic, err := topicDao.First(topicDao.Query)
				if err != nil {
					return err
				}
				// 判断当前题目有没有过期
				if time.Now().In(utils.LocationZone).After(topic.EndDateTime) {
					return errors.New("此题无法返修，因题目不在有效期内。")
				}
				//查询项目的答题时长
				var projectDao dao.Common[dao.SystemProject]
				projectDao.Tx = tx
				project, err := projectDao.First(map[string]interface{}{"project_id": topic.ProjectId})
				if err != nil {
					return err
				}

				var finishDateTime time.Time
				if time.Now().Add(time.Duration(project.CountdownAnswer) * time.Second).In(utils.LocationZone).After(topic.EndDateTime) {
					finishDateTime = topic.EndDateTime
				} else {
					finishDateTime = time.Now().Add(time.Duration(project.CountdownAnswer) * time.Second).In(utils.LocationZone)
				}
				topic.FinishTime = finishDateTime
				topic.Status = 4
				if err := topicDao.UpdateOne(topic.Id, map[string]interface{}{"finish_time": finishDateTime, "status": 4}).Error; err != nil {
					return err
				}
				//创建redis 过期事件
				expiration := topic.FinishTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				//key := fmt.Sprintf("task_topic_%d", topicId)
				key := utils.GenerateRedisKey(topicId, fmt.Sprintf("2"))
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 2, "status": 5})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
				return nil
			}(mysql.GetDB()); err != nil {
				return err
			}

		}
		return nil
	})
}

// 批量返修

func (d *TopicService) BatchTopicRepair(ch chan error, topicId uint, ExecutionDateTime, EndDateTime time.Time) {
	//defer wg.Done()
	_db := mysql.GetDB()
	err := _db.Transaction(func(tx *gorm.DB) error {
		//删除之前的任务
		tx.Model(&dao.SystemTask{}).Unscoped().Where(map[string]interface{}{"system_topic_id": topicId}).Delete(&dao.SystemTask{})
		//删除redis中的定时失效任务
		redis.RedisGClient.Del(fmt.Sprintf("task_topic@%d_%s", topicId, "6"))
		//删除redis中的定时生效任务
		redis.RedisGClient.Del(fmt.Sprintf("task_topic@%d_%s", topicId, "5"))
		//移除之前的任务的返修
		redis.RedisGClient.Del(fmt.Sprintf("task_topic@%d_%s", topicId, "3"))
		//更新题目的生效时间和截止时间
		current_DateTime := time.Now().In(utils.LocationZone)
		var status int
		if ExecutionDateTime.In(utils.LocationZone).After(current_DateTime) {
			status = 1
		} else {
			if EndDateTime.In(utils.LocationZone).After(current_DateTime) {
				status = 4
			} else {
				status = 7
			}
		}
		fmt.Println(current_DateTime, ExecutionDateTime, EndDateTime, status)
		// 状态为1的题目才能返修 或者是receiver_id 有值的时候才可以

		if err := tx.Model(&dao.SystemTopic{}).Where("id = ? and status = 1 AND receiver_id != ''", topicId).Updates(map[string]interface{}{"status": status, "effective_time": ExecutionDateTime, "end_date_time": EndDateTime}).Error; err != nil {
			return err
		}

		if ExecutionDateTime.After(current_DateTime) {
			//if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
			//	//执行时间在当日，创建redis 过期事件
			//	expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//	key := utils.GenerateRedisKey(topicId, fmt.Sprintf("3"))
			//	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 3, "status": 4})
			//	if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
			//		return setNX
			//	}
			//} else {
			//创建一个倒计时任务
			var task dao.SystemTask
			task.TaskType = 3
			task.SystemTopicId = topicId
			task.ExecutionDateTime = ExecutionDateTime
			task.ExecutionData = map[string]interface{}{"task_type": 3, "status": 4}
			if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
				return err
			}
			//}
		} else {
			var topicDao dao.Common[dao.SystemTopic]
			topicDao.Tx = tx
			topicDao.Query = map[string]interface{}{"id": topicId, "status": 4} //该题目必须是已经完成的
			topic, err := topicDao.First(topicDao.Query)
			if err != nil {
				fmt.Println("erererwerwe is %s", err)
				return err
			}
			//查询项目的答题时长
			var projectDao dao.Common[dao.SystemProject]
			projectDao.Tx = tx
			project, err := projectDao.First(map[string]interface{}{"project_id": topic.ProjectId})
			if err != nil {
				return err
			}
			var finishDateTime time.Time

			if time.Now().Add(time.Duration(project.CountdownAnswer) * time.Second).In(utils.LocationZone).After(topic.EndDateTime.In(utils.LocationZone)) {
				finishDateTime = topic.EndDateTime
			} else {
				finishDateTime = time.Now().Add(time.Duration(project.CountdownAnswer) * time.Second).In(utils.LocationZone)
			}
			topic.FinishTime = finishDateTime
			if err := topicDao.Update(map[string]interface{}{"finish_time": finishDateTime}).Error; err != nil {
				return err
			}
		}
		//题目截止时间处理
		if err := d.RegressionQuestionClose(topicId, EndDateTime); err != nil {
			return err
		}

		return nil
	})
	ch <- err
}

/*
 * 题目答题倒计时
 * TaskType 类型: 0->题目答题倒计时,管理员导入表格处理数据时的任务;1->指派;2->回归题库;3->返修;4->作废;5->题目生效时间更改题目状态;6->题目截止时间过期更改题目状态
 * Topic状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废 7已失效
 * 返修截止时间，超过截止时间，自动回归题库
 */

func (d *TopicService) TopicCountdownAnswer(topicId uint, ExecutionDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		if ExecutionDateTime.After(time.Now().In(utils.LocationZone)) {
			if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				//key := fmt.Sprintf("task_topic_%d", topicId)
				fmt.Println("题目ID %d ,执行时间 %d,当前时间%s", topicId, expiration, time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutTime))
				key := utils.GenerateRedisKey(topicId, fmt.Sprintf("0"))
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 0, "status": 5})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 0
				task.SystemTopicId = topicId
				task.ExecutionDateTime = ExecutionDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 0, "status": 5} //返修截止时间，超过截止时间，自动回归题库
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		} else {
			var topicDao dao.Common[dao.SystemTopic]
			topicDao.Tx = tx
			topicDao.Query = map[string]interface{}{"id": topicId, "status": []int{2, 3, 4, 5}}
			var topic dao.SystemTopic
			tx.Model(&dao.SystemTopic{}).Where("id = ?", topicId).First(&topic)
			var set map[string]interface{}
			// 题目截止时间在 题目预计完成时间 之后
			if topic.EndDateTime.After(ExecutionDateTime.In(utils.LocationZone)) {
				set = map[string]interface{}{"status": 5, "finish_time": nil}
			} else {
				if topic.FinishTime.Before(time.Now().In(utils.LocationZone)) {
					set = map[string]interface{}{"status": 7, "finish_time": nil}
				} else {
					set = map[string]interface{}{"status": 5, "finish_time": nil}
				}
			}
			set["receiver_id"] = ""
			if err := topicDao.Update(set).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

func (d *TopicService) TopicCountdownAnswer2(topicId uint, ExecutionDateTime time.Time, EndDateTime time.Time) error {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {

		if ExecutionDateTime.In(utils.LocationZone).After(time.Now().In(utils.LocationZone)) {
			if ExecutionDateTime.Format(timehandler.FormatLayoutDate) == time.Now().In(utils.LocationZone).Format(timehandler.FormatLayoutDate) {
				//执行时间在当日，创建redis 过期事件
				expiration := ExecutionDateTime.Unix() - time.Now().In(utils.LocationZone).Unix()
				//key := fmt.Sprintf("task_topic_%d", topicId)
				key := utils.GenerateRedisKey(topicId, fmt.Sprintf("0"))
				value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 0, "status": 5})
				if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
					return setNX
				}
			} else {
				//创建一个倒计时任务
				var task dao.SystemTask
				task.TaskType = 0
				task.SystemTopicId = topicId
				task.ExecutionDateTime = ExecutionDateTime
				task.ExecutionData = map[string]interface{}{"task_type": 0, "status": 5} //返修截止时间，超过截止时间，自动回归题库
				if err := tx.Model(&dao.SystemTask{}).Create(&task).Error; err != nil {
					return err
				}
			}
		} else {

			//执行时间在当前时间之前
			var topicDao dao.Common[dao.SystemTopic]
			topicDao.Tx = tx
			topicDao.Query = map[string]interface{}{"id": topicId, "status": []int{2, 3, 4, 5}}
			var set map[string]interface{}
			// 题目截止时间在 题目预计完成时间 之后
			if EndDateTime.After(ExecutionDateTime.In(utils.LocationZone)) {
				set = map[string]interface{}{"status": 5, "finish_time": nil}
			} else {
				if EndDateTime.Before(time.Now().In(utils.LocationZone)) {
					set = map[string]interface{}{"status": 7, "finish_time": nil}
				} else {
					set = map[string]interface{}{"status": 5, "finish_time": nil}
				}
			}
			set["receiver_id"] = ""
			if err := topicDao.Update(set).Error; err != nil {
				return err
			}
		}
		return nil
	})
}
